<template>
  <div class="analysis-attack-behavior">
    <Loading v-if="state.isLoading" />
    <div class="left-part">
      <h2>算子列表</h2>
      <ul class="operator-list">
        <li
          v-for="(item, index) in state.operatorArr"
          :class="state.activeName === item.value ? 'active' : ''"
          @click="handleClick(item.value, item.label)"
          :key="index">
          <img :src="state.activeName === item.value ? item.active : item.notActive" alt="show">
          {{ item.label }}
        </li>
      </ul>
    </div>

    <div class="right-part">
      <div class="t-p">
        <div class="title">
          <h2>分析模型</h2>
          <div class="btn-grp">
            <el-upload
              class="upload-demo"
              :show-file-list="false"
              :auto-upload="false"
              accept=".modl"
              :on-change="(file:any, fileList:any) => fileChange(file, fileList)"
              action="">
              <el-button type="primary">导入模型</el-button>
            </el-upload>
            <el-button type="primary" @click="getResult">运行</el-button>
          </div>
        </div>
        <ul v-if="typeof state.modelArr === 'object' && state.modelArr.length">
          <li
            v-for="(item, index) in state.modelArr"
            :key="index">
            <pre v-html="item"></pre>
          </li>
        </ul>
        <ul v-if="typeof state.modelArr === 'string' && state.modelArr">
          <pre v-html="state.modelArr"></pre>
        </ul>
        <p class="nodata" v-if="!state.modelArr || !state.modelArr.length">暂无数据</p>
      </div>
      <div class="b-p">
        <h2>分析结果</h2>
        <div class="container">
          <el-empty v-if="!state.container" description="暂无数据"></el-empty>
          <pre v-if="state.container" v-html="state.container"></pre>
        </div>
      </div>
    </div>

    <div class="steps">
      <h2>算子逻辑图</h2>
      <div class="img-box">
        <img v-if="state.isShowImg" :src="steps" alt="show">
        <p v-else class="nodata">暂无数据</p>
      </div>
    </div>

    <el-dialog
      :title="state.activeLabel + '算子'"
      v-model="state.dialogVisible"
      :width="state.logwidth + 'px'"
      :before-close="handleClose">
      <div class="log-line"></div>
      <AdvancedSearchsPlus
        :label="state.activeLabel"
        :searchFields="state.searchFields"
        @canceloperate="canceloperate"
        @savestep="savestep" />
    </el-dialog>
  </div>
</template>

<script lang="ts" setup>
import jiansuo1 from '../../../assets/img/jiansuo1.png'
import jiansuo2 from '../../../assets/img/jiansuo2.png'

import guanlian1 from '../../../assets/img/guanlian1.png'
import guanlian2 from '../../../assets/img/guanlian2.png'

import bianli1 from '../../../assets/img/bianli1.png'
import bianli2 from '../../../assets/img/bianli2.png'

import sort1 from '../../../assets/img/sort1.png'
import sort2 from '../../../assets/img/sort2.png'

import tiaojian1 from '../../../assets/img/tiaojian1.png'
import tiaojian2 from '../../../assets/img/tiaojian2.png'

import tongji1 from '../../../assets/img/tongji1.png'
import tongji2 from '../../../assets/img/tongji2.png'

import max1 from '../../../assets/img/max1.png'
import max2 from '../../../assets/img/max2.png'

import min1 from '../../../assets/img/min1.png'
import min2 from '../../../assets/img/min2.png'

import steps from '../../../assets/img/steps.png'

import AdvancedSearchsPlus from "./AdvancedSearchsPlus.vue";

interface aab {
  step:any,
  operatorArr:Array<any>,
  logwidthList:any,
  logwidth:number,
  activeName:number,
  activeLabel:string,
  searchFields:Array<any>,
  dialogVisible:boolean,
  modelArr: any,
  container:string,
  file: string,
  isShowImg:boolean,
  isLoading:boolean,
  temp:string
}

const state = reactive<aab>({
  step: steps,

  operatorArr: [
    {
      label: '检索',
      value: 1,
      active: jiansuo1,
      notActive: jiansuo2
    },
    {
      label: '关联',
      value: 2,
      active: guanlian1,
      notActive: guanlian2
    },
    {
      label: '遍历',
      value: 3,
      active: bianli1,
      notActive: bianli2
    },
    {
      label: '排序',
      value: 4,
      active: sort1,
      notActive: sort2
    },
    {
      label: '条件',
      value: 5,
      active: tiaojian1,
      notActive: tiaojian2
    },
    {
      label: '统计',
      value: 6,
      active: tongji1,
      notActive: tongji2
    },
    {
      label: '最大值',
      value: 7,
      active: max1,
      notActive: max2
    },
    {
      label: '最小值',
      value: 8,
      active: min1,
      notActive: min2
    }
  ],

  logwidthList: {
    1: 800,
    2: 500,
    3: 400,
    4: 400,
    5: 600,
    6: 600,
    7: 400,
    8: 400
  },
  logwidth: 800,
  activeName: 1,
  activeLabel: '检索',

  searchFields: [],
  dialogVisible: false,
  modelArr: [],
  container: '',
  file: '',
  isShowImg: false,
  isLoading: false,
  temp: `// 检索可疑的扫描行为
检索【数据源=‘初始数据库’，特征字符串=“Scan|20|quickly”】，结果RET1=【会话数据集合】；
遍历【RET1，源IP】
{
// 获取可疑IP的扫描行为数量
统计【RET1，源IP】，结果RESULTS=【源IP=IPx，数量】；
}
// 取扫描行为最频繁的IP
排序【RESULTS，数量】，取RESLULTS=【源IP=IPx，数量】；
//取排序后的最大值
最大值【RESULTS】, 结果RESULT1=【会话】；
// 查询指定IP与web服务端口的通联行为
检索【数据源=‘初始数据库’，目的port=80，源IP=IPx】，结果RET2=【会话数据集合】；
// 通过恶意样本与基于文件上传漏洞的攻击行为进行关联
关联【RET2，关联对象=文件，MD5=‘02C367FDEC298CD9C769F48F774ABA86’】，结果RET3=【会话数据集合】；
遍历【RET3，目的IP】
{
// 分析可疑的横向拓展攻击行为
检索【数据源=‘初始数据库’，源IP=IPx，协议=‘vnc’】，结果RET4=【会话数据集合】；
}
// 定位活跃的拓展攻击行为
排序【RET4，时间】，结果RET5=【会话数据】；
//取排序后的最大值
最大值【RET5】， 结果RESULT2=【会话】；`
})

const handleClick = (value:any, label:any) => {
  if (typeof state.modelArr !== 'object') {
    state.modelArr = []
  }
  state.activeName = value
  state.activeLabel = label

  state.searchFields = []

  state.logwidth = state.logwidthList[value]

  switch (value) {
    case 1:
      state.searchFields = [
        {
          label: '目的地址',
          value: 'target_ip'
        },
        {
          label: '源地址',
          value: 'origin_ip'
        },
        {
          label: '目的端口',
          value: 'target_port'
        },
        {
          label: '源端口',
          value: 'origin_port'
        },
        {
          label: '协议',
          value: 'protocol'
        },
        {
          label: '数据源',
          value: 'source'
        },
        {
          label: '特征字符串',
          value: 'characteristicstring'
        }
      ]
      break

    case 2:
      state.searchFields = [
        {
          label: '文件',
          value: '文件'
        },
        {
          label: 'URL',
          value: 'URL'
        },
        {
          label: '域名',
          value: '域名'
        },
        {
          label: '用户名',
          value: '用户名'
        },
        {
          label: '密码',
          value: '密码'
        },
        {
          label: '邮箱',
          value: '邮箱'
        }
      ]
      break

    case 3:
      state.searchFields = [
        {
          label: '目的地址',
          value: 'target_ip'
        },
        {
          label: '源地址',
          value: 'origin_ip'
        },
        {
          label: '目的端口',
          value: 'target_port'
        },
        {
          label: '源端口',
          value: 'origin_port'
        },
        {
          label: '协议',
          value: 'protocol'
        }
      ]
      break

    case 4:
      state.searchFields = [
        {
          label: '数量',
          value: 'num'
        },
        {
          label: '时间',
          value: 'time'
        }
      ]
      break

    case 5:
      state.searchFields = [
        {
          label: '目的地址',
          value: 'target_ip'
        },
        {
          label: '源地址',
          value: 'origin_ip'
        },
        {
          label: '目的端口',
          value: 'target_port'
        },
        {
          label: '源端口',
          value: 'origin_port'
        },
        {
          label: '协议',
          value: 'protocol'
        },
        {
          label: '数据源',
          value: 'source'
        },
        {
          label: '特征字符串',
          value: 'characteristicstring'
        }
      ]
      break

    case 6:
      state.searchFields = [
        {
          label: '目的地址',
          value: 'target_ip'
        },
        {
          label: '源地址',
          value: 'origin_ip'
        },
        {
          label: '目的端口',
          value: 'target_port'
        },
        {
          label: '源端口',
          value: 'origin_port'
        },
        {
          label: '协议',
          value: 'protocol'
        },
        {
          label: '数据源',
          value: 'source'
        }
      ]
      break
  }

  state.dialogVisible = true
}

const fileChange = (file:any, fileList:any) => {
  state.file = file
  state.modelArr = state.temp
}
const getResult = () => {
  if (state.modelArr !== state.temp) {
        state.container = ''
        return ElMessage({
          type: 'warning',
          message: '请检查模型代码'
        })
      }

      state.isLoading = true

      setTimeout(() => {
        state.isLoading = false
        state.isShowImg = true
        state.container = `// 检索可疑的扫描行为
检索【数据源=‘初始数据库’，特征字符串=“Scan|20|quickly”】，结果RET1=【会话数据集合】；
>结果：
>>源IP：119.29.29.29，源端口： 37782，目的IP： 192.168.56.11，目的端口：80
>>源IP：119.29.29.29，源端口： 37790，目的IP：192.168.56.150，目的端口：53
>>源IP：17.57.145.133，源端口： 37791，目的IP：192.168.56.150，目的端口：22
>>源IP：17.57.145.133，源端口： 37692，目的IP：192.168.56.133，目的端口：443
>>源IP：101.35.158.197，源端口： 37692，目的IP：192.168.56.11，目的端口：443
>>源IP：101.35.158.197，源端口： 37692，目的IP：192.168.56.150，目的端口：443
>>源IP：119.29.29.29，源端口： 37692，目的IP：192.168.56.133，目的端口：443

遍历【RET1，源IP=17.57.145.133】
{// 获取可疑IP的扫描行为数量
统计【RET1，源IP】，结果RESULTS=【源IP=119.29.29.29，数量】；
> 结果：
>> 源IP：17.57.145.133，数量20；
}
遍历【RET1，源IP=119.29.29.29】
{// 获取可疑IP的扫描行为数量
统计【RET1，源IP】，结果RESULTS=【源IP=17.57.145.133，数量】；
> 结果：
>> 源IP：119.29.29.29，数量110；
}
遍历【RET1，源IP=101.35.158.197】
{// 获取可疑IP的扫描行为数量
统计【RET1，源IP】，结果RESULTS=【源IP=101.35.158.197，数量】；
> 结果：
>> 源IP：101.35.158.197，数量2；
}

// 取扫描行为最频繁的IP
排序【RESULTS】，取RESLULTS=【源IP，数量】；
> 结果：
>> 源IP：119.29.29.29，数量110；
>> 源IP：17.57.145.133，数量20；
>> 源IP：101.35.158.197，数量2；

// 取排序后结果的最大值
最大值【RESULTS】，取RESLULT1=【源IP，数量】；
> 结果：
>> 源IP：119.29.29.29，数量110；

// 查询指定IP与web服务端口的通联行为
检索【数据源='初始数据库'，目的port=80，源IP=119.29.29.29】，结果RET2=【会话数据集合】；
> 结果：
>> 源IP：119.29.29.29，源端口： 37782，目的IP： 192.168.56.11，目的端口：80
>> 源IP：119.29.29.29，源端口： 37780，目的IP： 192.168.56.11，目的端口：80
>> 源IP：119.29.29.29，源端口： 37781，目的IP： 192.168.56.11，目的端口：80
>> 源IP：119.29.29.29，源端口： 37778，目的IP： 192.168.56.11，目的端口：80

// 通过恶意样本与基于文件上传漏洞的攻击行为进行关联
关联【RET2，关联对象=文件，MD5=‘02C367FDEC298CD9C769F48F774ABA86’】，结果RET3=【会话数据集合】；
> 结果：
>> 源IP：119.29.29.29，源端口： 37782，目的IP： 192.168.56.11，目的端口：80，文件MD5
>> 源IP：119.29.29.29，源端口： 37780，目的IP： 192.168.56.11，目的端口：80，文件MD5

遍历【RET3，目的IP】
{
// 分析可疑的横向拓展攻击行为
检索【数据源=‘初始数据库’，源IP=192.168.56.11，协议=‘vnc’】，结果RET4=【会话数据集合】；
> 结果：
>> 源IP： 192.168.56.11，源端口： 37782，目的IP： 192.168.56.12，目的端口：3379，时间：1694599538
>>  源IP： 192.168.56.11，源端口： 37752，目的IP： 192.168.56.12，目的端口：3379，时间：1694599518
}

// 定位活跃的拓展攻击行为
排序【RET4，时间】，取结果RET5=【会话数据】；
>  结果：
>>  源IP： 192.168.56.11，源端口： 37782，目的IP： 192.168.56.12，目的端口：3379，时间：1694599538
>>  源IP： 192.168.56.11，源端口： 37752，目的IP： 192.168.56.12，目的端口：3379，时间：1694599518

//取排序后的最大值
最大值【RET5，时间】，取最新时间结果RESULT2=【会话数据】；
>  结果：
>>  源IP： 192.168.56.11，源端口： 37782，目的IP： 192.168.56.12，目的端口：3379，时间：1694599538
`
      }, 1000)
}

const handleClose = (done:any) => {
  done()
}

const canceloperate = () => {
  if (state.file && typeof state.modelArr === 'object' && !state.modelArr.length) {
    state.modelArr = state.temp
    state.isShowImg = true
  }
  state.dialogVisible = false
}

const savestep = (value:string) => {
  state.modelArr.push(value)

  state.isShowImg = false

  state.dialogVisible = false
}
</script>

<style scoped lang="scss">
.analysis-attack-behavior {
  position: relative;
  display: flex;
  height: 100%;
  .left-part {
    width: 250px;
    height: 100%;
    margin-right: 10px;
    border: 1px solid #eaeaeb;
    padding: 8px 10px 10px 10px;
    box-sizing: border-box;
    h2 {
      text-align: center;
      font-size: 16px;
      color: #0960bd;
      padding: 3px 0;
    }
    .operator-list {
      margin-top: 6px;
      display: flex;
      flex-wrap: wrap;
      justify-content: space-between;
      .active {
        background-color: #edf6ff;
      }
      li {
        width: 91px;
        height: 100px;
        margin-bottom: 5px;
        background-color: #fbfcfb;
        color: #555;
        font-size: 14px;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        cursor: pointer;
        padding: 3px 10px;
        img {
          width: 32px;
          display: inline-block;
          margin-bottom: 4px;
          object-fit: cover;
        }
      }
    }
  }
  .right-part {
    width: calc(75% - 270px);
    height: 100%;
    h2 {
      color: #0960bd;
      font-size: 16px;
    }
    .t-p {
      padding: 8px 10px 14px 10px;
      height: 30%;
      box-sizing: border-box;
      min-height: 200px;
      border: 1px solid #eaeaeb;
      margin-bottom: 10px;
      :deep(.el-empty) {
        height: calc(100% - 32px);
        position: relative;
        top: -8px;
      }
      ul {
        height: calc(100% - 44px);
        overflow-y: auto;
      }
      li {
        margin-bottom: 10px;
        font-size: 12px;
      }
      pre {
        font-size: 14px;
        font-family: NSimSun !important;
      }
      .title {
        display: flex;
        justify-content: space-between;
        margin-bottom: 10px;
        align-items: center;
        border-bottom: 1px solid #eaeaeb;
        padding-bottom: 6px;
        .btn-grp {
          display: flex;
          :deep(.el-button) {
            margin-left: 10px;
          }
          :deep(.el-button:nth-child(2)) {
            width: 80px;
          }
        }
      }
    }
    .b-p {
      height: calc(70% - 12px);
      max-height: calc(100% - 212px);
      border: 1px solid #eaeaeb;
      padding: 8px 10px 10px 10px;
      box-sizing: border-box;
      h2 {
        padding: 8px 0 12px 0;
        border-bottom: 1px solid #eaeaeb;
        margin-bottom: 10px;
      }
      .container {
        display: flex;
        flex-direction: column;
        justify-content: center;
        height: calc(100% - 44px);
        pre {
          height: 100%;
          overflow-y: auto;
          font-size: 14px;
          font-family: NSimSun !important;
        }
      }
    }

    :deep(.el-empty__image) {
      width: 13% !important;
      min-width: 100px;
    }
    :deep(.el-empty__description) {
      margin-top: 10px;
      font-size: 14px;
    }
  }

  .steps {
    width: 25%;
    border: 1px solid #eaeaeb;
    padding: 10px 10px 20px 10px;
    margin-left: 10px;
    box-sizing: border-box;
    h2 {
      margin-bottom: 14px;
      width: 100%;
      font-size: 16px;
      padding: 6px 0 10px 0;
      border-bottom: 1px solid #eaeaeb;
      color: #0960bd;
    }
    .img-box {
      width: 100%;
      height: 100%;
      display: flex;
      align-items: center;
      flex-direction: column;
      img {
        // width: 85%;
        height: 100%;
      }
      height: calc(100% - 44px);
      overflow-y: auto;
    }
  }

  .nodata {
    color: #909399;
    text-align: center;
    height: 100%;
    display: block;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
  }

  :deep(.el-dialog__body) {
    padding: 0px 20px 20px 20px;
  }
  :deep(.el-dialog__title) {
    font-size: 17px;
  }
  .log-line {
    width: 100%;
    border-bottom: 1px solid rgb(173, 170, 170);
    margin-bottom: 26px;
  }
}
</style>